#include <string.h>

#include "lib.h"
#include "bjserv.h"
#include "bjconn.h"
#include "bjsql.h"
#include "bjgame.h"
#include "bjhand.h"
#include "bjsaved.h"
#include "bjproto.h"
#include "stdncerr.h"
#include "opts.h"
#include "log.h"
#include "bjrules.h"

#include "XMLTranslator.h"

#include "badpacketmsgs.h"



static BJSQL* tracker = (BJSQL*)0;

//
// TODO: use results from tracker-> calls!
//

typedef struct _info
{
	String		login;
	PID			pid;
	SESSIONID	sessionId;
	bool8		forMoney;
} Info, *pInfo;



void
BJServer::startTracker()
{
	ServerOpts::load();

	tracker = new BJSQL(ServerOpts::dbdsn,
		ServerOpts::dblogin, ServerOpts::dbpasswd);

	// CSN-8891
	webServiceCall = new WebServiceCall();
}

void
BJServer::stopTracker()
{
	delete tracker;
	tracker = 0;

	delete webServiceCall;
	webServiceCall = 0;
}

bool8
BJServer::initSuccess()
{
	if (tracker && tracker->initOK())
		return Server::initSuccess();
	else
	{
		Log::msgError("Failed to connect to the database.  Aborting.");
		return false;
	}
}

bool8
BJConnection::parseAnsiCasinoLogin
(
	int32*	Err
)
{
	//offset
	//Skip tag
	int k=1;
	//tag
	//uint8 tag = msgbuf[k++];

	//proto

	////////////////////////////////////////
	//FORCE THE CLIENT PROTOCOL VERSION TO
	//MATCH THE SERVER PROTOCOL VERSION
	//THIS IS A COMPLETE AND TOTAL HACK
	//FOR TESTING DEBUGGING ONLY
	#if DEBUG
	#define FORCE_PROTOCOL_VERSION_MATCH (0)
	#if(FORCE_PROTOCOL_VERSION_MATCH)
		msgbuf[k+2]=PROTO_VERSION1;
		msgbuf[k+3]=PROTO_VERSION2;
	#endif
	#endif
	////////////////////////////////////////

	if
	(
		msgbuf[k++]	!= APP1				||
		msgbuf[k++]	!= APP2				||
		msgbuf[k++]	!= PROTO_VERSION1	||
		msgbuf[k++]	!= PROTO_VERSION2
	)
	{
		*Err = LOGINERR_BADVERSION;
		DEBUGMSG(("Login: incorrect version: %c%c.%c%c",
				msgbuf[1],msgbuf[2],msgbuf[3],msgbuf[4]));
		return false;
	}

	//blackjack machine id
	m_machid = msgbuf[k++];

	Info* info = new Info();
	if (!info)
	{
		*Err = LOGINERR_TRYLATER;
		return false;
	}

	char login[PIDLEN + 1];
	memcpy(login, &msgbuf[k], PIDLEN);
	login[PIDLEN] = '\0';
	k += PIDLEN;

	info->login = login;

	info->forMoney = (bool8)(msgbuf[k++] != 0);

	// CSN-10426: with this modification, we don't need iClientID sent by the client, so we skip it
	String sClientTypeIntAPI = String::emptyString;
	k++;	// Skip ClientID

	if (xmlTranslator && xmlTranslator->UsingFunPID())
	{
		// CSN-7076: New Authentication (fun play)
		bool8 result;
		tracker->lock();
		result = tracker->getAvailableFunID( info->login );
		tracker->unlock();
		if (!result)
		{
			*Err = LOGINERR_CONTACTCUSTSERVICE;
			delete info;
			info = 0;
			return false;
		}
	}
	else
	{
		// CSN-7075: New Authentication
		String sToken = String::emptyString;
		k =+ sToken.deserialize(&msgbuf[k]);
		
		// CSN-8909: Look for clientType in Integration API
		if (!wsCall()->Authenticate(sToken, info->login, sClientTypeIntAPI, m_sCurrency))
		{
			bool8 bAuth = false;
			
			// CSN-12167: connect with no token? In that case, white-listed PID is sent in <Token> field
			#ifdef DEBUGSPIN
			if (ServerOpts::bAllowTesting)
			{
				bAuth = tracker->isFreeFromAuthentication(sToken);					
				if (bAuth)
					info->login = sToken;
			}
			#endif

			if (!bAuth)
			{
				*Err = LOGINERR_CONTACTCUSTSERVICE;
				delete info;
				info = 0;
				return false;
			}
		}
	}

	if (tracker)
	{
		bool8 result;

		tracker->lock();
		//result = tracker->validateLogin(info->login, info->sessionId, info->pid);
		result = tracker->createRTGSession(info->forMoney, info->login, info->sessionId, sClientTypeIntAPI);
		tracker->unlock();

		if (!result)
		{
			*Err = LOGINERR_CONTACTCUSTSERVICE;
			delete info;
			info = 0;
			return false;
		}
	}

	info->pid = info->login;
	casinoSpecific = info;
    #ifdef FORCEDSHOE 
    m_pid=info->login;
    #endif
	return true;
}

bool8
BJConnection::parseUnicodeCasinoLogin
(
	int32*	Err
)
{
	//offset
	//skip tag
	int k=2;
	//tag
	//uint8 tag = msgbuf[k++];

	//proto

	////////////////////////////////////////
	//FORCE THE CLIENT PROTOCOL VERSION TO
	//MATCH THE SERVER PROTOCOL VERSION
	//THIS IS A COMPLETE AND TOTAL HACK
	//FOR TESTING DEBUGGING ONLY
	#if DEBUG
	#define FORCE_PROTOCOL_VERSION_MATCH (0)
	#if(FORCE_PROTOCOL_VERSION_MATCH)
		msgbuf[k+2]=PROTO_VERSION1;
		msgbuf[k+3]=PROTO_VERSION2;
	#endif
	#endif
	////////////////////////////////////////

	if
	(
		msgbuf[k++]	!= APP1				||
		msgbuf[k++]	!= APP2				||
		msgbuf[k++]	!= PROTO_VERSION1	||
		msgbuf[k++]	!= PROTO_VERSION2
	)
	{
		*Err = LOGINERR_BADVERSION;
		DEBUGMSG(("Login: incorrect version: %c%c.%c%c",
				msgbuf[1],msgbuf[2],msgbuf[3],msgbuf[4]));
		return false;
	}

	//blackjack machine id
	m_machid = msgbuf[k++];

	Info* info = new Info();
	if (!info)
	{
		*Err = LOGINERR_TRYLATER;
		return false;
	}

	k += info->login.deserialize(&msgbuf[k]);

	info->forMoney = (bool8)(msgbuf[k++] != 0);

	// CSN-10426: with this modification, we don't need iClientID sent by the client, so we skip it
	String sClientTypeIntAPI = String::emptyString;
	k++;	// Skip ClientID

	if (xmlTranslator && xmlTranslator->UsingFunPID())
	{
		// CSN-7076: New Authentication (fun play)
		bool8 result;
		tracker->lock();

		result = tracker->getAvailableFunID( info->login );
		tracker->unlock();
		if (!result)
		{
			*Err = LOGINERR_CONTACTCUSTSERVICE;
			delete info;
			info = 0;
			return false;
		}
	}
	else
	{
		// CSN-7075: New Authentication
		String sToken = String::emptyString;
		k =+ sToken.deserialize(&msgbuf[k]);

		// CSN-8909: Look for clientType in Integration API
		if (!wsCall()->Authenticate(sToken, info->login, sClientTypeIntAPI, m_sCurrency))
		{
			bool8 bAuth = false;
			
			// CSN-12167: connect with no token? In that case, white-listed PID is sent in <Token> field
			#ifdef DEBUGSPIN
			if (ServerOpts::bAllowTesting)
			{
				bAuth = tracker->isFreeFromAuthentication(sToken);					
				if (bAuth)
					info->login = sToken;
			}
			#endif

			if (!bAuth)
			{
				*Err = LOGINERR_CONTACTCUSTSERVICE;
				delete info;
				info = 0;
				return false;
			}
		}
	}

	if (tracker)
	{
		//int32 result;
		bool8 result;

		tracker->lock();
		//result = tracker->validateLogin(info->login, info->sessionId, info->pid);
		result = tracker->createRTGSession(info->forMoney, info->login, info->sessionId, sClientTypeIntAPI);
		tracker->unlock();

		if (!result)
		{
			*Err = LOGINERR_CONTACTCUSTSERVICE;
			delete info;
			return false;
		}
	}

	info->pid = info->login;
	casinoSpecific = info;
    #ifdef FORCEDSHOE 
    m_pid=info->login;
    #endif
	return true;
}


void
BJConnection::removeCasinoSpecific()
{
	delete (pInfo)casinoSpecific;

	casinoSpecific = (void*)0;
}

bool8 
BJConnection::isForMoney()
{
	return ((pInfo) casinoSpecific)->forMoney;
}

bool8
BJConnection::shouldSaveGameData()
{
	if ( isForMoney() )
	{
		return true;
	}

	if ( ServerOpts::bSaveFunData )
	{
		return true;
	}

	return false;
}

int32
BJConnection::encode(uint8* In, uint8* Out, int32 Len)
{
	memcpy(Out, In, Len);
	return Len;
}

int32
BJConnection::decode(uint8* In, uint8* Out, int32 Len)
{
	memcpy(Out, In, Len);
	return Len;
}

bool8
BJConnection::trackGetForcedHands
(
	char*	pForcedHandDealer,
	char*	pForcedHandPlayer,
	int32	nBytesPerHand
)
{
	int32 result = BJSQL::ExecFailed;

	if (tracker)
	{
		tracker->lock();

		result = tracker->getForcedHands
		(
			pForcedHandDealer,
			pForcedHandPlayer,
			nBytesPerHand
		);

		tracker->unlock();
	}

	if (result == BJSQL::NoError)
		return true;
	else
		return false;
}

bool8
BJConnection::trackGetBalance( int32 *balance )
{
	pInfo info = (pInfo)casinoSpecific;
	int32 result = BJSQL::ExecFailed;
	int32 comp;
	*balance = 0;

	if (tracker && info)
	{
		tracker->lock();
		result = tracker->getBalance(ServerOpts::casinoId,
			info->pid, info->forMoney, balance, &comp);
		tracker->unlock();
	}

	return (bool8)(result == BJSQL::NoError);
}

int32
BJConnection::trackAdjustBalance
(
	int32 Amount
)
{
	pInfo info = (pInfo)casinoSpecific;
	int32 result = BJSQL::ExecFailed;
	int32 bal = 0, comp = 0;

	if (tracker && info)
	{
		tracker->lock();
		result = tracker->adjustBalance
		(
			ServerOpts::casinoId,
			info->pid,
			info->forMoney,
			Amount,
			&bal,
			&comp
		);
		tracker->unlock();
	}

	if (result == BJSQL::NoError)
		return bal;
	return 0;
}


bool8
BJConnection::trackGetPlayerLimits
(
	int32* minBet,
	int32* maxBet,
	int32* compFactor
)
{
	pInfo info = (pInfo)casinoSpecific;
	int32 result = BJSQL::ExecFailed;

	if (tracker && info)
	{
		tracker->lock();
		result = tracker->getPlayerLimits
		(
			info->pid,
			GAMEID,
			GetMachId(),
			minBet,
			maxBet,
			compFactor
		);
		tracker->unlock();
	}

	return (bool8)(result == BJSQL::NoError);
}

bool8
BJConnection::trackGetMachineOptions( uint8	machid,	uint8* ruleSetId, uint8* nDecks, uint8 *nBets )
{
	int32 result = BJSQL::ExecFailed;

	if (tracker)
	{
		tracker->lock();
		result = tracker->getMachineOptions(machid,ruleSetId,nDecks,nBets);
		tracker->unlock();
	}

	return (bool8)(result == BJSQL::NoError);
}

//psharpless 12/20/06 Case: 16101.  Needed for Perfect Pairs side bet.
bool8
BJConnection::trackGetSideBetOptions(uint8 machid, uint8* paytable)
{
	int32 result = BJSQL::ExecFailed;

	if(tracker)
	{
		tracker->lock();
		result = tracker->getSideBetOptions(machid,paytable);
		tracker->unlock();
	}

	return (bool8)(result == BJSQL::NoError);
}


bool8
BJConnection::trackGetRuleSet
(
	uint8		ruleSetId,
	BJRules*	pRules
)
{
	pInfo info = (pInfo)casinoSpecific;
	int32 result = BJSQL::ExecFailed;

	if (tracker && info)
	{
		tracker->lock();
		result = tracker->getRuleSet(ruleSetId,pRules);
		tracker->unlock();
	}

	return (bool8)(result == BJSQL::NoError);
}


// kharmon.  02-13-07.  #16101.  Added nSideBet for amount of new Perfect Pairs sidebet option.
bool8
BJConnection::trackNewGame( int32 bet, int32 *balance, int32 *pBonusBalanceBet, char* gid, uint8 iBJBet, int32 nSideBet )
{
	pInfo info = (pInfo)casinoSpecific;
	int32 result = BJSQL::ExecFailed;

	if (tracker && info)
	{
		if( shouldSaveGameData())
		{
			uint8 nBets = game->getnBets();	// number of bets placed on the table
			char *tieID = game->GetGID(0);	// first bet's GID (used to tie the game records)

			tracker->lock();

			result = tracker->createGame( ServerOpts::casinoId,info->pid,info->forMoney,
				GetMachId(),info->sessionId,info->forMoney ? compFactor : 0,
                                          gid, bet, pBonusBalanceBet, iBJBet, nBets, tieID, nSideBet );
	        
	        
			tracker->unlock();
		}
		else
		{
			result = BJSQL::NoError;
		}
	}

	return (bool8)(result == BJSQL::NoError);
}

bool8
BJConnection::trackInsuranceState( char* gid,uint8 state,int32 Payout,int32 *balance )
{
	int32 error = BJSQL::ExecFailed;

	if( tracker )
	{
		if(shouldSaveGameData())
		{
			tracker->lock();
			error = tracker->setInsuranceState(gid,state,Payout,balance );
			tracker->unlock();
		}
		else
		{
			error = BJSQL::NoError;
		}
	}

	return (bool8)(error == BJSQL::NoError);
}

/**************************************************************************************************************
 * @fn BJConnection::trackSideBetResult( char* acGID,uint8 ucState,int32 nPayout,int32 *pnBalance )
 * 
 * This method is called to record the results of the player's side bet, if he made one.
 *
 * @param  acGID     -  (in)  the gamenum that this bet will be associated with in the database.
 * @param  ucState   -  (in)  represents what kind of win or loss the player had, see PerfectPairWinTypes enum.
 * @param  nPayout   -  (in)  money amount of win, zero on loss.
 * @param  pnBalance -  (out) player balance after adjusting for win or loss.
 *
 * kharmon.  02-13-07.  #16101.  Added for new Perfect Pairs sidebet option.
 **************************************************************************************************************/
bool8
BJConnection::trackSideBetResult( char* acGID,uint8 ucState,int32 nPayout,int32 *pnBalance )
{
	int32 nError = BJSQL::ExecFailed;

	if( tracker )
	{
		if(shouldSaveGameData())
		{
			tracker->lock();
			nError = tracker->setSideBetResult(acGID, ucState, nPayout, pnBalance );
			tracker->unlock();
		}
		else
		{
			nError = BJSQL::NoError;
		}
	}

	return (bool8)(nError == BJSQL::NoError);
}


bool8
BJConnection::trackDealerDeal( BJHand* Dealer, char* gid )
{
	int32 error = BJSQL::ExecFailed;

	if( tracker )
	{
		if( shouldSaveGameData())
		{
			tracker->lock();

			uint8	nCards		= 0;
			uint8*	pCards		= 0;

			//tell the dealer hand to indicate which cards are unknown to the player
			Dealer->SetCardFacingBits();
			nCards = (uint8)Dealer->getCount();
			pCards = Dealer->getCards();

            // kharmon.  10-23-06.  #16151.  We still want to do this dealer card save,
            // BUT, if a card is face down, only save that face-down bit, don't save the suit and rank.
            uint8 *paucCards = new uint8[nCards];
            memcpy(paucCards, pCards, nCards);
            for(int nI=0;nI<nCards;++nI)
            {

                if((paucCards[nI]&0x80)!=0)
                {
                    paucCards[nI] = paucCards[nI]&0x80;
                }
            }

			error = tracker->createDealerHand( gid, nCards, paucCards );

            delete [] paucCards;
            paucCards = NULL;

			Dealer->ClrCardFacingBits();

			tracker->unlock();
		}
		else
		{
			error = BJSQL::NoError;
		}
	}

	return (error == BJSQL::NoError);
}


bool8
BJConnection::trackPlayerDeal( BJHand* Player, int32 *balance, char* gid )
{
	int32 error = BJSQL::ExecFailed;
	int32 error2 = BJSQL::ExecFailed;

	if( tracker )
	{
		if( shouldSaveGameData())
		{
			tracker->lock();

			uint8	nBets		= 0;
			uint8	nCards		= 0;
			uint8*	pCards		= 0;
			uint8	bet			= 0;
			uint8	hit			= 0;
			uint8	stand		= 0;
			uint8	doubled		= 0;
			uint8	split		= 0;
			uint8	surrender	= 0;
			uint8	raise		= 0;
			/// [2013-07-10] Charles. Added for supporting 'Zappit Rackcard'.
			uint8	zap = 0;
			
			int32	bonusBalanceBet = Player->GetBonusBalanceBet();

			*balance		= 0;

			//tell the player hand to indicate which cards are unknown to the player
			Player->SetCardFacingBits();
			nBets	= (uint8)Player->GetNBets();
			nCards	= (uint8)Player->getCount();
			pCards	= Player->getCards();

			BJHand* pHand = Player;

			bet			= pHand->wasAction( BJF_BET		);
			hit			= pHand->wasAction( BJF_HIT		);
			stand		= pHand->wasAction( BJF_STAND		);
			doubled		= pHand->wasAction( BJF_DOUBLE		);
			split		= pHand->wasAction( BJF_SPLIT		);
			surrender	= pHand->wasAction( BJF_SURRENDER	);
			raise		= pHand->wasAction( BJF_RAISE		);
			/// [2013-07-10] Charles. Added for supporting 'Zappit Rackcard'.
			zap		= pHand->wasAction( BJF_ZAP);

			/// [2013-07-10] Charles. Added 'zap' argument for supporting 'Zappit Rackcard'.
			error = tracker->savePlayerHand( gid,	0, nBets, nCards, pCards, bet, 
				hit, stand, doubled, split, surrender,	raise, zap, Player->updateBalance(), balance, &bonusBalanceBet );

			if ( Player->updateBalance() )
			{
				Player->balanceUpdated();
				Player->SetBonusBalanceBet(bonusBalanceBet);
			}
			Player->ClrCardFacingBits();
			tracker->unlock();
		}
		else
		{
			error = BJSQL::NoError;
		}
	}

	// Try to save the rest of the game state even if the hand save failes
    error2 = trackSaveGame();

    return (error == error2 == BJSQL::NoError);
}

bool8
BJConnection::trackPlayerHand( char* gid,BJHand* pHand,bool8 adjustBalance,
                              int32 *balance, int8 nextBet)
{
	int32 error = BJSQL::ExecFailed;
	int32 error2 = BJSQL::ExecFailed;

	int32 bonusBalanceBet = pHand->GetBonusBalanceBet();

	if( tracker )
	{
		if(shouldSaveGameData())
		{
			tracker->lock();

			error = tracker->savePlayerHand
			(
				gid,
				(uint8)pHand->GetNHand(),
				(uint8)pHand->GetNBets(),
				(uint8)pHand->getCount(),
				(uint8*)pHand->getCards(),
				(uint8)pHand->wasAction( BJF_BET		),
				(uint8)pHand->wasAction( BJF_HIT		),
				(uint8)pHand->wasAction( BJF_STAND		),
				(uint8)pHand->wasAction( BJF_DOUBLE		),
				(uint8)pHand->wasAction( BJF_SPLIT		),
				(uint8)pHand->wasAction( BJF_SURRENDER	),
				(uint8)pHand->wasAction( BJF_RAISE		),
				(uint8)pHand->wasAction( BJF_ZAP),				/// [2013-07-10] Charles. Added for supporting 'Zappit Rackcard'.
				(bool8)adjustBalance,
				balance,
				&bonusBalanceBet
			);

			tracker->unlock();
		}
		else
		{
			trackGetBalance(balance);
			error = BJSQL::NoError;
		}

		// "savePlayerHand" returns bonus balance inly if adjustBalance=true
		if( adjustBalance )
		{
			pHand->SetBonusBalanceBet(bonusBalanceBet);
		}
	}

	// Try to save the rest of the game state even if the hand save failes

    error2 = trackSaveGame(nextBet);

	return (error == error2 == BJSQL::NoError);
}

bool8
BJConnection::trackPlayerHands( char* gid, BJHand* pPlayer, int32 splitCount )
{
	int32 balance;
	bool8 ok, adjustBalance;

	// This is a SPLIT -- only adjust the balance on one hand - the new one
	// which has "updateBalance" flag set to true !!
	while (pPlayer)
	{

		adjustBalance = pPlayer->updateBalance();

		ok = trackPlayerHand( gid, pPlayer, adjustBalance, &balance );

		if (!ok)
			return false;

		if( adjustBalance )
			pPlayer->balanceUpdated();


		pPlayer = (BJHand*)pPlayer->getNextHand();
	}

	return true;
}

bool8
BJConnection::trackPayout( char* gid,BJHand* pHand, int32 payout)
{
	int32 error = BJSQL::ExecFailed;

	if( tracker )
	{
		if(shouldSaveGameData())
		{
			tracker->lock();

			error = tracker->setPlayerPayout(gid, pHand->GetNHand(), payout	);

			tracker->unlock();
		}
		else
		{
			//if not saving fun play data, we must update the account with the payout
			if(pHand->GetPayout() >= 0)
				trackAdjustBalance(payout);

			error = BJSQL::NoError;
		}
	}

	return (error == BJSQL::NoError);
}

bool8
BJConnection::trackGameDone( BJHand* Dealer, char* gid )
{
	int32 error = BJSQL::ExecFailed;
	int32 error2 = BJSQL::ExecFailed;

	if( tracker )
	{
		if(shouldSaveGameData())
		{
			tracker->lock();

			error = tracker->saveDealerHand( gid,(uint8)Dealer->getCount(),(uint8*)Dealer->getCards() );
			error2 = tracker->gameDone( gid );

			tracker->unlock();
		}
		else
		{
			error = error2 = BJSQL::NoError;
		}
	}

	return (error == error2 == BJSQL::NoError);
}

bool8
BJConnection::trackHasSavedGame(int32* err, int32 *pnGameNum)
{
	pInfo info = (pInfo)casinoSpecific;
	BJSavedGame sg;
	bool8 exists = false;
	int32 result = BJSQL::ExecFailed;
	*err = 0;
	BJRules* pRules=NULL;

	if( !(tracker && info) )
	{
		*err = LOGINERR_CONTACTCUSTSERVICE;
		return false;
	}

	//if we should not save fun game data we should not try to
	//retore saved fun game data
	if(! shouldSaveGameData())
	{
		return false;
	}

	tracker->lock();

	result = tracker->hasSavedGame( info->pid,info->forMoney,GetMachId(),&sg,&exists );

    if (result == BJSQL::BadSavedGame)
    {
        // kharmon.  05-04-07.  #19358.  Return new "bad saved game" error message.
        *err = ERR_BADSAVEDGAME;
        *pnGameNum = atoi(sg.BJBets[0].gid);
        goto cleanup;
    }
	else if (result != BJSQL::NoError)
	{
		*err = LOGINERR_CONTACTCUSTSERVICE;
		goto cleanup;
	}

	if (!exists)
	{
		goto cleanup;
	}

	pRules = GetRuleSet();
	if (pRules == NULL)
	{
		*err = LOGINERR_CONTACTCUSTSERVICE;
		goto cleanup;
	}

	game = new BJGame(this, pRules, &sg);
	if (!game)
	{
		*err = LOGINERR_CONTACTCUSTSERVICE;
		exists = false;
		goto cleanup;
	}

cleanup:

	tracker->unlock();
	return exists;
}

bool8
BJConnection::trackSaveGame( int8 nextBet )
{
	pInfo info = (pInfo)casinoSpecific;
	BJSavedGame sg;
	int32 result = BJSQL::ExecFailed;

	if (!game)
		return true;

	if(! shouldSaveGameData())
		return true;

	if (tracker && info)
	{
		game->save(&sg, nextBet);

		tracker->lock();
		result = tracker->saveGame(info->pid, info->forMoney, &sg);
		tracker->unlock();

		return (bool8)(result == BJSQL::NoError);
	}
	return false;		// todo: return "failed"
}


void
BJConnection::trackaddBadPacket(int32 error_reason, char MessageType, char *msgbuf, int32 msglen)
{
	pInfo info = (pInfo)casinoSpecific;

	if (tracker && info)
	{
		tracker->lock();
		tracker->addBadPacket(GAMEID, 0x00, sBadPacketMessages[error_reason].message, sBadPacketMessages[error_reason].severity, info->pid, MessageType, (uint8*)msgbuf, msglen);
		tracker->unlock();
	}
}

void
BJConnection::trackResetSavedGame()
{
	int32 result;

	if (!game)	return ;

	if( tracker )
	{
		tracker->lock();

        result = tracker->resetSavedGame(game->GetGID(0));

		tracker->unlock();
	}
}

int32
BJConnection::trackValidateLogin()
{
    pInfo info = (pInfo)casinoSpecific;
    int32 result = BJSQL::ExecFailed;

    if (tracker && info)
    {
        tracker->lock();
		result = tracker->validateLogin(info->login, info->sessionId, info->pid);
        tracker->unlock();
    }

    return result;
}

int32
BJConnection::trackValidateSession()
{
    pInfo info = (pInfo)casinoSpecific;
    int32 result = BJSQL::ExecFailed;

    if (tracker && info)
    {
        tracker->lock();
		result = tracker->validateSession(info->pid, info->sessionId);
        tracker->unlock();
    }

    return result;
}

bool8	
BJConnection::getLocale( localCurrency* lc, int32* chipValues, int32 numChipValues )
{
	bool8 ok = false;
    if (tracker)
    {
		tracker->lock();
		ok = ( TrackSQL::NoError == tracker->getLocale( lc, chipValues ) );
		tracker->unlock();
	}
	return ok;
}

void BJConnection::trackLogoutSession()
{
    pInfo info = (pInfo)casinoSpecific;

	if (tracker && info && !info->login.isEmpty())
    {
        tracker->lock();
		tracker->logout(ServerOpts::casinoId, info->login, info->forMoney, String::emptyString, info->sessionId);
        tracker->unlock();
    }
}